#!/usr/bin/env node
/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

"use strict";
import { resolve, join, delimiter } from 'node:path';
import { createHash } from 'node:crypto';
import { readdirSync, statSync, existsSync, readFileSync, renameSync, mkdirSync, writeFileSync, rmSync, copyFileSync } from 'node:fs';
import { execSync } from 'node:child_process';
import { argv, env, execPath } from 'node:process';

function execCommand(command, workdir) {
  console.log(`Executing command: ${command}, cwd: ${workdir}`);
  return execSync(command,
    { cwd: workdir, stdio: 'inherit' });
}

function getNpm() {
  const pathDirs = process.env.PATH.split(delimiter);
  const npmDir = pathDirs.find(dir => {
    const npmPath = join(dir, 'npm');
    const npmExists = existsSync(npmPath) && statSync(npmPath).isFile();
    const notContainsDeveco = !dir.toLowerCase().includes('deveco');

    return npmExists && notContainsDeveco;
  });
  return npmDir ? `"${join(npmDir, 'npm')}"` : 'npm';
}

function getHvigorConfigHash() {
  const configPath = resolve('hvigor', 'hvigor-config.json5');
  if (existsSync(configPath)) {
    // 读取 hvigor-config.json5 文件内容
    const configContent = readFileSync(configPath);
    // 计算文件内容的 hash 值
    const currentHash = createHash('sha256').update(configContent).digest('hex');
    return currentHash;
  }
  return '';
}

function checkLock(hash) {
  // 检查锁文件是否存在
  if (existsSync(resolve('.plugin-build.lock'))) {
    // 读取锁文件内容
    const lockContent = readFileSync(resolve('.plugin-build.lock'), { encoding: 'utf-8' });
    // 比较 hash 值
    if (lockContent.includes(hash)) {
      return true;
    }
  }
  return false;
}

function generateBuildLock(hash) {
  writeFileSync(resolve('.plugin-build.lock'), hash, { encoding: 'utf-8' });
}

function clearDir(projectDir, targetDir) {
  console.log(`Clearing ${targetDir} directory...`);
  const dirPath = resolve(projectDir, targetDir);
  if (existsSync(dirPath)) {
    rmSync(dirPath, { recursive: true, force: true });
  }
}

function ensureDir(projectDir, targetDir) {
  const dirPath = resolve(projectDir, targetDir);
  if (!existsSync(dirPath)) {
    console.log(`Creating ${targetDir} directory...`);
    mkdirSync(dirPath, { recursive: true });
    console.log(`Directory ${dirPath} created successfully.`);
  } else {
    console.log(`Directory ${dirPath} already exists.`);
  }
}

function findModuleDirs(dir, result = []) {
  const files = readdirSync(dir);

  files.forEach(file => {
    const filePath = join(dir, file);
    const stat = statSync(filePath);

    if (stat.isDirectory()) {
      if (existsSync(join(filePath, 'package.json')) && !filePath.includes('node_modules')) {
        result.push(filePath);
      }
      findModuleDirs(filePath, result);
    }
  });
  return result;
}

function buildArtifact(moduleDir) {
  console.log(`Building artifact in ${moduleDir}...`);
  if (!existsSync(join(moduleDir, 'package.json'))) {
    console.log(`skip ${moduleDir}: package.json`);
    return;
  }
  const distDir = resolve(moduleDir, 'dist');
  if (existsSync(distDir)) {
    console.log(`clean dist: ${distDir}`);
    rmSync(distDir, { recursive: true, force: true });
  }
  execCommand(`${getNpm()} install --loglevel verbose`, moduleDir);
  execCommand(`npx tsc`, moduleDir);
  execCommand(`npm pack`, moduleDir);
}

function moveArtifact(moduleDir) {
  console.log(`Moving artifact in ${moduleDir}...`);
  const packageData = readFileSync(resolve(moduleDir, 'package.json'));
  const npmPackageInfo = JSON.parse(packageData);
  const packageFileName =
    `${npmPackageInfo.name.replaceAll('@', '').replaceAll('/', '-')}-${npmPackageInfo.version}.tgz`;
  renameSync(resolve(moduleDir, packageFileName),
    resolve('tpc', 'outputs', 'plugin', packageFileName));
}

function signArtifact() {
  const artifactsDir = resolve('tpc', 'outputs', 'plugin');
  console.log(`Signing artifacts in ${artifactsDir}...`);
  const artifactFiles = readdirSync(artifactsDir);
  for (const file of artifactFiles) {
    const fullPath = join(artifactsDir, file);
    const stats = statSync(fullPath);
    if (stats.isFile()) {
      let content = readFileSync(fullPath);
      let hashing = createHash('sha256').update(content).digest('hex');
      writeFileSync(resolve(fullPath, '..', `${file}.${hashing.substring(0, 8)}.sha256`), hashing,
        { encoding: 'utf-8' });
    }
  }
}

function copyDocs() {
  console.log(`Copying README.md to HMRouterLibrary...`);
  copyFileSync(resolve('README.md'), resolve('HMRouterLibrary', 'README.md'));
  console.log(`Copying PluginConfig.md to HMRouterPlugin...`)
  copyFileSync(resolve('docs', 'PluginConfig.md'), resolve('HMRouterPlugin', 'README.md'));
}

function main() {
  console.log('Process args:', argv);
  console.log('Process env:', env);
  console.log('Process execPath:', execPath);
  const projectDir = resolve();
  console.log('Project directory: ', projectDir);
  const hash = getHvigorConfigHash();
  const isLocked = checkLock(hash);
  if (isLocked) {
    console.log('Skip build, hvigor config not changed');
    return;
  }
  const moduleDirs = findModuleDirs(projectDir);
  console.log('Node modules found in project: ', moduleDirs);
  clearDir(projectDir, join('tpc', 'outputs', 'plugin'));
  ensureDir(projectDir, join('tpc', 'outputs', 'plugin'));
  for (const moduleDir of moduleDirs) {
    buildArtifact(moduleDir);
    moveArtifact(moduleDir);
  }
  signArtifact();
  generateBuildLock(hash);
}

main();
copyDocs();

